#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ether.h>
#include <arpa/inet.h>
#include <unistd.h>

#define MAX 1600

#define ERR(errmsg) do{\
                        perror(errmsg);\
                        exit(-1);\
                    }while(0)

int main(int argc, char const *argv[])
{
    int sockfd;
    //创建原始套接字
    if((sockfd = socket(AF_PACKET,SOCK_RAW,htons(ETH_P_ALL))) < 0)
    {
        ERR("fail to socket");
    }
    
    unsigned char buf_recv[MAX] = "";
    while(1)
    {
        printf("*************************************************\n");
        //接收以太网数据包
        if(recvfrom(sockfd,buf_recv,MAX,0,NULL,NULL) < 0)
        {
            ERR("fail to recvfrom");
        }
    
        unsigned char dest_mac[18] = "";
        unsigned char src_mac[18] = "";
        unsigned short type;
        //获取目的mac地址，源mac地址，协议类型
        sprintf(dest_mac,"%x:%x:%x:%x:%x:%x",buf_recv[0],buf_recv[1],buf_recv[2],buf_recv[3],buf_recv[4],buf_recv[5]);
        sprintf(src_mac,"%x:%x:%x:%x:%x:%x",buf_recv[6],buf_recv[7],buf_recv[8],buf_recv[9],buf_recv[10],buf_recv[11]);
        type = ntohs(*(unsigned short*)(buf_recv+12));
        printf("MAC: %s --> %s\n",src_mac,dest_mac);
        printf("protocol_type: %#x\n",type);

        //IP数据报
        if(type == 0x0800)
        {
            //获取IP数据报头的信息
            unsigned char head_len = (*(unsigned char*)(buf_recv+14)&0x0f)*4;   //首部长度
            unsigned short IP_len = ntohs(*(unsigned short*)(buf_recv+16));     //总长度
            unsigned char type_ip = (*(unsigned char*)(buf_recv+23));     //协议类型（ICMP/IGMP/TCP/UDP）
            unsigned char src_ip[16] = "";      //源ip地址
            unsigned char dest_ip[16] = "";     //目的ip地址
            sprintf(src_ip,"%d.%d.%d.%d",buf_recv[26],buf_recv[27],buf_recv[28],buf_recv[29]);
            sprintf(dest_ip,"%d.%d.%d.%d",buf_recv[30],buf_recv[31],buf_recv[32],buf_recv[33]);
            printf("ip: %s --> %s\n",src_ip,dest_ip);
            printf("ip数据报首部长度:%d,总长度:%d\n",head_len,IP_len);

            
            if(type_ip == 1)
            {
                printf("ICMP报文\n");
            }
            else if(type_ip == 2)
            {
                printf("IGMP报文\n");
            }
            else if(type_ip == 16)
            {
                printf("TCP报文\n");
                unsigned short src_port = ntohs(*(unsigned short*)(buf_recv+34));     //源端口
                unsigned short dest_port = ntohs(*(unsigned short*)(buf_recv+36));    //目的端口
                printf("port: %d --> %d\n",src_port,dest_port);
            }
            else if(type_ip == 17)
            {
                printf("UDP报文\n");
                unsigned short src_port = ntohs(*(unsigned short*)(buf_recv+34));    //源端口
                unsigned short dest_port = ntohs(*(unsigned short*)(buf_recv+36));   //目的端口
                printf("port: %d --> %d\n",src_port,dest_port);
            }
            
        }
        //ARP数据报
        else if(type == 0x0806)
        {
            printf("ARP数据报\n");
        }
        //RARP数据报
        else
        {
            printf("RARP数据报\n");
        }
        printf("*************************************************\n");
    }
    close(sockfd);
    return 0;
}

